<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<!--[if IE]><meta http-equiv="X-UA-Compatible" content="IE=edge"><![endif]-->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="generator" content="Asciidoctor 1.5.8">
<title>Sample setups</title>
<link rel="stylesheet" href="css/spring.css">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css">
</head>
<body class="article toc2 toc-left">
<div id="header">
<h1>Sample setups</h1>
<div id="toc" class="toc2">
<div id="toctitle">Table of Contents</div>
<ul class="sectlevel1">
<li><a href="#concourse-pipeline-cf">Concourse Pipeline (Cloud Foundry)</a>
<ul class="sectlevel2">
<li><a href="#concourse-pipeline-step-by-step-cf">Step-by-step</a></li>
</ul>
</li>
<li><a href="#concourse-pipeline-k8s">Concourse Pipeline (Kubernetes)</a>
<ul class="sectlevel2">
<li><a href="#step-by-step-k8s">Step-by-step</a></li>
<li><a href="#concourse-start-k8s">Concourse in K8S (Kubernetes)</a></li>
</ul>
</li>
<li><a href="#kubernetes-setup">Kubernetes Setup</a>
<ul class="sectlevel2">
<li><a href="#kubernetes-cli-installation">Kubernetes CLI Installation</a></li>
<li><a href="#start-minikube-k8s">Kubernetes Cluster Setup</a></li>
<li><a href="#run-minikube">Run Minikube</a></li>
<li><a href="#certificates-and-workers">Certificates and Workers</a></li>
<li><a href="#generate-minikube-namespaces">Generate Minikube Namespaces</a></li>
</ul>
</li>
<li><a href="#the-demo-setup-cloud-foundry">The demo setup (Cloud Foundry)</a>
<ul class="sectlevel2">
<li><a href="#deploying-production-applications-to-pcf-dev">Deploying Production Applications to PCF Dev</a></li>
<li><a href="#running-prometheus-on-cf">Running Prometheus on CF</a></li>
<li><a href="#running-grafana-on-cf">Running Grafana on CF</a></li>
</ul>
</li>
<li><a href="#the-demo-setup-kubernetes">The demo setup (Kubernetes)</a>
<ul class="sectlevel2">
<li><a href="#deploying-production-applications-to-minikube">Deploying Production Applications to Minikube</a></li>
<li><a href="#running-prometheus-on-kubernetes">Running Prometheus on Kubernetes</a></li>
<li><a href="#running-grafana-on-kubernetes">Running Grafana on Kubernetes</a></li>
</ul>
</li>
</ul>
</div>
</div>
<div id="content">
<div id="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>In these sections you will see examples of setups
for different platforms.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="concourse-pipeline-cf"><a class="link" href="#concourse-pipeline-cf">Concourse Pipeline (Cloud Foundry)</a></h2>
<div class="sectionbody">
<div class="admonitionblock important">
<table>
<tr>
<td class="icon">
<i class="fa icon-important" title="Important"></i>
</td>
<td class="content">
In this chapter, we assume that you deploy your application
to Cloud Foundry PaaS.
</td>
</tr>
</table>
</div>
<div id="concourse" class="paragraph">
<p>The Cloud Pipelines repository contains opinionated
Concourse pipeline definitions. Those jobs form an empty pipeline and an
opinionated sample pipeline one that you can use in your company.</p>
</div>
<div class="paragraph">
<p>There following projects take part in the  <code>microservice setup</code> for this demo.</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://github.com/spring-cloud-samples/github-analytics">Github Analytics</a>: The app that has a REST endpoint and uses messaging&#8201;&#8212;&#8201;part of our business application.</p>
</li>
<li>
<p><a href="https://github.com/spring-cloud-samples/github-webhook">Github Webhook</a>: Project that emits messages that are used by Github Analytics&#8201;&#8212;&#8201;part of our business application.</p>
</li>
<li>
<p><a href="https://github.com/spring-cloud-samples/github-eureka">Eureka</a>: Simple Eureka Server. This is an infrastructure application.</p>
</li>
<li>
<p><a href="https://github.com/spring-cloud-samples/github-analytics-stub-runner-boot">Github Analytics Stub Runner Boot</a>: Stub Runner Boot server to be used for tests with Github Analytics and uses Eureka and Messaging. This is an infrastructure application.</p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="concourse-pipeline-step-by-step-cf"><a class="link" href="#concourse-pipeline-step-by-step-cf">Step-by-step</a></h3>
<div class="paragraph">
<p>If you want only to run the demo as far as possible by using PCF Dev and Docker Compose, do the following:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><a href="#concourse-fork-cf">Fork repos</a></p>
</li>
<li>
<p><a href="#concourse-start-cf">Start Concourse and Artifactory</a></p>
</li>
<li>
<p><a href="#concourse-deploy-cf">Deploy infra to Artifactory</a></p>
</li>
<li>
<p><a href="#concourse-pcfdev-cf">Start PCF Dev (if you don&#8217;t want to use an existing one)</a></p>
</li>
<li>
<p><a href="#concourse-fly-cf">Setup the <code>fly</code> CLI</a></p>
</li>
<li>
<p><a href="#concourse-credentials-cf">Setup your <code>credentials.yml</code></a></p>
</li>
<li>
<p><a href="#concourse-build-cf">Build the Pipeline</a></p>
</li>
<li>
<p><a href="#concourse-run-cf">Run the <code>github-webhook</code> Pipeline</a></p>
</li>
</ol>
</div>
<div class="sect3">
<h4 id="concourse-fork-cf"><a class="link" href="#concourse-fork-cf">Fork Repositories</a></h4>
<div class="paragraph">
<p>Four applications compose the pipeline</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://github.com/spring-cloud-samples/github-webhook">Github Webhook</a></p>
</li>
<li>
<p><a href="https://github.com/spring-cloud-samples/github-analytics/">Github Analytics</a></p>
</li>
<li>
<p><a href="https://github.com/spring-cloud-samples/github-eureka">Github Eureka</a></p>
</li>
<li>
<p><a href="https://github.com/spring-cloud-samples/github-analytics-stub-runner-boot">Github Stub Runner Boot</a></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>You need to fork only the following repositories, because only then can you tag and push the tag to the repository:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://github.com/spring-cloud-samples/github-webhook">Github Webhook</a></p>
</li>
<li>
<p><a href="https://github.com/spring-cloud-samples/github-analytics/">Github Analytics</a></p>
</li>
</ul>
</div>
</div>
<div class="sect3">
<h4 id="concourse-start-cf"><a class="link" href="#concourse-start-cf">Start Concourse and Artifactory</a></h4>
<div class="paragraph">
<p>You can run Concourse + Artifactory locally. To do so, run the
<code>start.sh</code> script from this repository. The following listing shows the script:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">git clone https://github.com/CloudPipelines/concourse
cd concourse/demo
./setup_docker_compose.sh
./start.sh 192.168.99.100</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>The <code>setup_docker_compose.sh</code> script should be run only once, to allow
generation of keys.</p>
</div>
<div class="paragraph">
<p>The <code>192.168.99.100</code> param is an example of an external URL of Concourse
(equal to the Docker-Machine IP in this example).</p>
</div>
<div class="paragraph">
<p>Then Concourse runs on port <code>8080</code>, and Artifactory runs on <code>8081</code>.</p>
</div>
<div class="sect4">
<h5 id="concourse-deploy-cf"><a class="link" href="#concourse-deploy-cf">Deploy the infra JARs to Artifactory</a></h5>
<div class="paragraph">
<p>When Artifactory is running, run the <code>tools/deploy-infra.sh</code> script from this repo.
The following listing shows the script:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">git clone https://github.com/CloudPipelines/concourse
cd concourse
./tools/deploy-infra.sh</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>As a result, both <code>eureka</code> and <code>stub runner</code> repos are cloned, built,
and uploaded to Artifactory.</p>
</div>
</div>
</div>
<div class="sect3">
<h4 id="concourse-pcfdev-cf"><a class="link" href="#concourse-pcfdev-cf">Start PCF Dev</a></h4>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
You can skip this step if you have CF installed and do not want to use PCF Dev.
The only thing you have to do is to set up spaces.
</td>
</tr>
</table>
</div>
<div class="admonitionblock warning">
<table>
<tr>
<td class="icon">
<i class="fa icon-warning" title="Warning"></i>
</td>
<td class="content">
Servers often run run out of resources at the stage step.
If that happens, <a href="#resources">clear some apps from PCF Dev and continue</a>.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>You have to download and start PCF Dev, as described  <a href="https://pivotal.io/platform/pcf-tutorials/getting-started-with-pivotal-cloud-foundry-dev/install-pcf-dev">here.</a></p>
</div>
<div class="paragraph">
<p>The default credentials for PCF Dev are as follows:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">username: user
password: pass
email: user
org: pcfdev-org
space: pcfdev-space
api: api.local.pcfdev.io</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>You can start the PCF Dev as follows:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">cf dev start</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>You must create three separate spaces, as follows:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">cf login -a https://api.local.pcfdev.io --skip-ssl-validation -u admin -p admin -o pcfdev-org

cf create-space pcfdev-test
cf set-space-role user pcfdev-org pcfdev-test SpaceDeveloper
cf create-space pcfdev-stage
cf set-space-role user pcfdev-org pcfdev-stage SpaceDeveloper
cf create-space pcfdev-prod
cf set-space-role user pcfdev-org pcfdev-prod SpaceDeveloper</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>You can also run the <code>./tools/cf-helper.sh setup-spaces</code> script to create the spaces.</p>
</div>
</div>
<div class="sect3">
<h4 id="concourse-fly-cf"><a class="link" href="#concourse-fly-cf">Setup the <code>fly</code> CLI</a></h4>
<div class="paragraph">
<p>If you go to the Concourse website, you should see something resembling the following image:</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/concourse/running_concourse.png" alt="running concourse">
</div>
</div>
<div class="paragraph">
<p>You can click one of the icons (depending on your OS) to download <code>fly</code>, which is the Concourse CLI. Once you download that (and maybe, depending on your OS, add it to your PATH) you can run the following command:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">fly --version</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>If <code>fly</code> is properly installed, it should print out the version.</p>
</div>
</div>
<div class="sect3">
<h4 id="concourse-credentials-cf"><a class="link" href="#concourse-credentials-cf">Set up Your <code>credentials.yml</code> File</a></h4>
<div class="paragraph">
<p>The repository comes with <code>credentials-sample-cf.yml</code>, which is set up with sample data (mostly credentials) that are applicable for PCF Dev. Copy this file to a new file called <code>credentials.yml</code> (the file is added to <code>.gitignore</code> so that you cannot push it with your passwords) and edit it as you wish. For our demo, set up the following:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><code>app-url</code>: URL pointing to your forked <code>github-webhook</code> repository.</p>
</li>
<li>
<p><code>github-private-key</code>: Your private key to clone and tag GitHub repositorys.</p>
</li>
<li>
<p><code>repo-with-binaries</code>: The IP is set to the defaults for Docker Machine. You should update it to point to your setup.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>If you do not have a Docker Machine, run th <code>./whats_my_ip.sh</code> script to
get an external IP that you can pass to your <code>repo-with-binaries</code>, instead of the default
Docker Machine IP.</p>
</div>
<div class="paragraph">
<p>The following table describes the environment variables required by the scripts:</p>
</div>
<table class="tableblock frame-topbot grid-all stretch">
<colgroup>
<col style="width: 33.3333%;">
<col style="width: 33.3333%;">
<col style="width: 33.3334%;">
</colgroup>
<thead>
<tr>
<th class="tableblock halign-left valign-top">Property Name</th>
<th class="tableblock halign-left valign-top">Property Description</th>
<th class="tableblock halign-left valign-top">Default value</th>
</tr>
</thead>
<tbody>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>PAAS_TEST_API_URL</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The URL to the CF Api for TEST env</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>api.local.pcfdev.io</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>PAAS_STAGE_API_URL</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The URL to the CF Api for STAGE env</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>api.local.pcfdev.io</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>PAAS_PROD_API_URL</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The URL to the CF Api for PROD env</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>api.local.pcfdev.io</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>PAAS_TEST_ORG</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Name of the org for the test env</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>pcfdev-org</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>PAAS_TEST_SPACE_PREFIX</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Prefix of the name of the CF space for the test env to which the app name will be appended</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>cloud-pipelines-test</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>PAAS_STAGE_ORG</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Name of the org for the stage env</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>pcfdev-org</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>PAAS_STAGE_SPACE</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Name of the space for the stage env</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>cloud-pipelines-stage</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>PAAS_PROD_ORG</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Name of the org for the prod env</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>pcfdev-org</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>PAAS_PROD_SPACE</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Name of the space for the prod env</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>cloud-pipelines-prod</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>REPO_WITH_BINARIES_FOR_UPLOAD</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">URL to repo with the deployed jars</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code><a href="https://192.168.99.100:8081/artifactory/libs-release-local" class="bare">https://192.168.99.100:8081/artifactory/libs-release-local</a></code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>M2_SETTINGS_REPO_ID</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">The id of server from Maven settings.xml</p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>artifactory-local</code></p></td>
</tr>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>PAAS_HOSTNAME_UUID</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Additional suffix for the route. In a shared environment the default routes can be already taken</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tbody>
<tfoot>
<tr>
<td class="tableblock halign-left valign-top"><p class="tableblock"><code>BUILD_OPTIONS</code></p></td>
<td class="tableblock halign-left valign-top"><p class="tableblock">Additional options you would like to pass to the Maven / Gradle build</p></td>
<td class="tableblock halign-left valign-top"></td>
</tr>
</tfoot>
</table>
<div class="paragraph">
<p>The right column shows the default values for PCF Dev that we set in the <code>credentials-sample-cf.yml</code>. <code>PAAS_HOSTNAME_UUID</code> and <code>BUILD_OPTIONS</code> have no default values.</p>
</div>
</div>
<div class="sect3">
<h4 id="concourse-build-cf"><a class="link" href="#concourse-build-cf">Build the Pipeline</a></h4>
<div class="paragraph">
<p>Log in (for example, for a Concourse instance running at <code>192.168.99.100</code>&#8201;&#8212;&#8201;if you do not provide any value, <code>localhost</code> is assumed). If you run the login script, it assumes that either <code>fly</code> is on your <code>PATH</code> or it is in the same folder as the script. The following example shows how to specify an IP address for the login script:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">./login.sh 192.168.99.100</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Next, run the command to create the pipeline, as follows:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">./set_pipeline.sh</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Then you can create a <code>github-webhook</code> pipeline under the <code>docker</code> alias, using the provided <code>credentials.yml</code> file.
You can override these values in exactly that order (for example <code>./set-pipeline.sh some-project another-target some-other-credentials.yml</code>)</p>
</div>
</div>
<div class="sect3">
<h4 id="concourse-run-cf"><a class="link" href="#concourse-run-cf">Run the <code>github-webhook</code> Pipeline</a></h4>
<div class="paragraph">
<p>The following images show the various steps involved in running the <code>github-webhook</code> pipeline:</p>
</div>
<div class="paragraph">
<p>&#160;
&#160;</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/concourse/concourse_login.png" alt="concourse login">
</div>
<div class="title">Step 1: Click <code>Login</code></div>
</div>
<div class="paragraph">
<p>&#160;
&#160;</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/concourse/concourse_team_main.png" alt="concourse team main">
</div>
<div class="title">Step 2: Pick <code>main</code> team</div>
</div>
<div class="paragraph">
<p>&#160;
&#160;</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/concourse/concourse_user_pass.png" alt="concourse user pass">
</div>
<div class="title">Step 3: Log in with <code>concourse</code> user and <code>changeme</code> password</div>
</div>
<div class="paragraph">
<p>&#160;
&#160;</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/concourse/concourse_pipeline.png" alt="concourse pipeline">
</div>
<div class="title">Step 4: Your screen should look more or less like this</div>
</div>
<div class="paragraph">
<p>&#160;
&#160;</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/concourse/start_pipeline.png" alt="start pipeline">
</div>
<div class="title">Step 5: Unpause the pipeline by clicking in the top lefr corner and then clicking the <code>play</code> button</div>
</div>
<div class="paragraph">
<p>&#160;
&#160;</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/concourse/generate_version.png" alt="generate version">
</div>
<div class="title">Step 6: Click 'generate-version'</div>
</div>
<div class="paragraph">
<p>&#160;
&#160;</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/concourse/run_pipeline.png" alt="run pipeline">
</div>
<div class="title">Step 7: Click <code>+</code> sign to start a new build</div>
</div>
<div class="paragraph">
<p>&#160;
&#160;</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/concourse/concourse_pending.png" alt="concourse pending">
</div>
<div class="title">Step 8: The job is pending</div>
</div>
<div class="paragraph">
<p>&#160;
&#160;</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/concourse/job_running.png" alt="job running">
</div>
<div class="title">Step 9: Job is pending in the main screen</div>
</div>
<div class="paragraph">
<p>&#160;
&#160;</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/concourse/running_pipeline.png" alt="running pipeline">
</div>
<div class="title">Step 10: Job is running in the main screen</div>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="concourse-pipeline-k8s"><a class="link" href="#concourse-pipeline-k8s">Concourse Pipeline (Kubernetes)</a></h2>
<div class="sectionbody">
<div class="admonitionblock important">
<table>
<tr>
<td class="icon">
<i class="fa icon-important" title="Important"></i>
</td>
<td class="content">
In this chapter, we assume that you deploy your application
to Kubernetes PaaS
</td>
</tr>
</table>
</div>
<div id="concourse-k8s" class="paragraph">
<p>The Cloud Pipelines repository contains opinionated
Concourse pipeline definitions. Those jobs form an empty pipeline and an
opinionated sample pipeline that you can use in your company.</p>
</div>
<div class="paragraph">
<p>The following projects take part in the <code>microservice setup</code> for this demo:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://github.com/spring-cloud-samples/github-analytics-kubernetes">Github Analytics</a>: The application that has a REST endpoint and uses messaging&#8201;&#8212;&#8201;part of our business application.</p>
</li>
<li>
<p><a href="https://github.com/spring-cloud-samples/github-webhook-kubernetes">Github Webhook</a>: Project that emits messages that are used by Github Analytics&#8201;&#8212;&#8201;part of our business application.</p>
</li>
<li>
<p><a href="https://github.com/spring-cloud-samples/github-eureka">Eureka</a>: Simple Eureka Server. This is an infrastructure application.</p>
</li>
<li>
<p><a href="https://github.com/spring-cloud-samples/github-analytics-stub-runner-boot">Github Analytics Stub Runner Boot</a>: Stub Runner Boot server to be used for tests with Github Analytics and uses Eureka and Messaging. This is an infrastructure application.</p>
</li>
</ul>
</div>
<div class="sect2">
<h3 id="step-by-step-k8s"><a class="link" href="#step-by-step-k8s">Step-by-step</a></h3>
<div class="paragraph">
<p>If you want only to run the demo as far as possible by using PCF Dev and Docker Compose, do the following:</p>
</div>
<div class="olist arabic">
<ol class="arabic">
<li>
<p><a href="#concourse-fork-k8s">Fork repos</a></p>
</li>
<li>
<p><a href="#concourse-start-k8s">Start Concourse and Artifactory</a></p>
</li>
<li>
<p><a href="#concourse-pipeline-fly-k8s">Setup the <code>fly</code> CLI </a></p>
</li>
<li>
<p><a href="#concourse-pipeline-credentials-k8s">Setup your <code>credentials.yml</code> </a></p>
</li>
<li>
<p><a href="#concourse-pipeline-build-k8s">Setup the pipeline </a></p>
</li>
<li>
<p><a href="#concourse-pipeline-run-k8s">Run the <code>github-webhook</code> pipeline</a></p>
</li>
</ol>
</div>
<div class="sect3">
<h4 id="fork-repos-k8s"><a class="link" href="#fork-repos-k8s">Fork Repositories</a></h4>
<div id="concourse-fork-k8s" class="paragraph">
<p>Four applications compose the pipeline:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://github.com/spring-cloud-samples/github-webhook-kubernetes">Github Webhook</a></p>
</li>
<li>
<p><a href="https://github.com/spring-cloud-samples/github-analytics-kubernetes/">Github Analytics</a></p>
</li>
<li>
<p><a href="https://github.com/spring-cloud-samples/github-eureka">Github Eureka</a></p>
</li>
<li>
<p><a href="https://github.com/spring-cloud-samples/github-analytics-stub-runner-boot-classpath-stubs">Github Stub Runner Boot</a></p>
</li>
</ul>
</div>
<div class="paragraph">
<p>You need to fork only the following repositories, because only then can you tag and push the tag to the repository:</p>
</div>
<div class="ulist">
<ul>
<li>
<p><a href="https://github.com/spring-cloud-samples/github-webhook-kubernetes">Github Webhook</a></p>
</li>
<li>
<p><a href="https://github.com/spring-cloud-samples/github-analytics-kubernetes/">Github Analytics</a></p>
</li>
</ul>
</div>
</div>
</div>
<div class="sect2">
<h3 id="concourse-start-k8s"><a class="link" href="#concourse-start-k8s">Concourse in K8S (Kubernetes)</a></h3>
<div class="paragraph">
<p>The simplest way to deploy Concourse to K8S is to use <a href="https://github.com/kubernetes/helm">Helm</a>.
Once you have Helm installed and your <code>kubectl</code> is pointing to the
cluster, run the following command to install the Concourse cluster in your K8S cluster:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ helm install stable/concourse --name concourse</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Once the script is done, you should see the following output</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">1. Concourse can be accessed:

  * Within your cluster, at the following DNS name at port 8080:

    concourse-web.default.svc.cluster.local

  * From outside the cluster, run these commands in the same shell:

    export POD_NAME=$(kubectl get pods --namespace default -l "app=concourse-web" -o jsonpath="{.items[0].metadata.name}")
    echo "Visit http://127.0.0.1:8080 to use Concourse"
    kubectl port-forward --namespace default $POD_NAME 8080:8080

2. Login with the following credentials

  Username: concourse
  Password: concourse</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Follow the steps and log in to Concourse under <a href="http://127.0.0.1:8080" class="bare">http://127.0.0.1:8080</a>.</p>
</div>
<div class="sect3">
<h4 id="deploying-artifactory-to-k8s"><a class="link" href="#deploying-artifactory-to-k8s">Deploying Artifactory to K8S</a></h4>
<div class="paragraph">
<p>You can use Helm also to deploy Artifactory to K8S, as follows:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ helm install --name artifactory --set artifactory.image.repository=docker.bintray.io/jfrog/artifactory-oss stable/artifactory</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>After you run this command, you should see the following output:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">NOTES:
Congratulations. You have just deployed JFrog Artifactory Pro!

1. Get the Artifactory URL by running these commands:

   NOTE: It may take a few minutes for the LoadBalancer IP to be available.
         You can watch the status of the service by running 'kubectl get svc -w nginx'
   export SERVICE_IP=$(kubectl get svc --namespace default nginx -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
   echo http://$SERVICE_IP/

2. Open Artifactory in your browser
   Default credential for Artifactory:
   user: admin
   password: password</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Next, you need to set up the repositories.</p>
</div>
<div class="paragraph">
<p>First, access the Artifactory URL and log in with
a user name of <code>admin</code> and a password of <code>password</code>.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/concourse/artifactory_quick_setup.png" alt="artifactory quick setup">
</div>
<div class="title">Figure 1. Click on Quick Setup</div>
</div>
<div class="paragraph">
<p>Then, click on Maven setup and click <code>Create</code>.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/concourse/artifactory_maven_repo.png" alt="artifactory maven repo">
</div>
<div class="title">Figure 2. Create the <code>Maven</code> Repository</div>
</div>
</div>
<div class="sect3">
<h4 id="concourse-pipeline-fly-k8s"><a class="link" href="#concourse-pipeline-fly-k8s">Setup the <code>fly</code> CLI</a></h4>
<div class="paragraph">
<p><a id="fly"></a> If you go to the Concourse website you should see something resembling the following:</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/concourse/running_concourse.png" alt="running concourse">
</div>
</div>
<div class="paragraph">
<p>You can click one of the icons (depending on your OS) to download <code>fly</code>, which is the Concourse CLI. Once you download that (and maybe added it to your PATH, depending on your OS) you can run the following command:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">fly --version</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>If <code>fly</code> is properly installed, it should print out the version.</p>
</div>
</div>
<div class="sect3">
<h4 id="concourse-pipeline-credentials-k8s"><a class="link" href="#concourse-pipeline-credentials-k8s">Setup your <code>credentials.yml</code></a></h4>
<div class="paragraph">
<p>We made a sample credentials file called <code>credentials-sample-k8s.yml</code>
prepared for <code>k8s</code>. You can use it as a base for your <code>credentials.yml</code>.</p>
</div>
<div class="paragraph">
<p>To allow the Concourse worker&#8217;s spawned container to connect to the
Kubernetes cluster, you must pass the CA contents and the
auth token.</p>
</div>
<div class="paragraph">
<p>To get the contents of CA for GCE, run the following command:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ kubectl get secret $(kubectl get secret | grep default-token | awk '{print $1}') -o jsonpath='{.data.ca\.crt}' | base64 --decode</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>To get the auth token, run the following command:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ kubectl get secret $(kubectl get secret | grep default-token | awk '{print $1}') -o jsonpath='{.data.token}' | base64 --decode</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Set that value under <code>paas-test-client-token</code>, <code>paas-stage-client-token</code>, and <code>paas-prod-client-token</code></p>
</div>
</div>
<div class="sect3">
<h4 id="concourse-pipeline-build-k8s"><a class="link" href="#concourse-pipeline-build-k8s">Build the pipeline</a></h4>
<div class="paragraph">
<p>After running Concourse, you should get the following output in your terminal:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ export POD_NAME=$(kubectl get pods --namespace default -l "app=concourse-web" -o jsonpath="{.items[0].metadata.name}")
$ echo "Visit http://127.0.0.1:8080 to use Concourse"
$ kubectl port-forward --namespace default $POD_NAME 8080:8080
Visit http://127.0.0.1:8080 to use Concourse</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Log in (for example, for Concourse running at <code>127.0.0.1</code>&#8201;&#8212;&#8201;if you do not provide any value, <code>localhost</code> is assumed). If you run this script, it assumes that either <code>fly</code> is on your <code>PATH</code> or that it is in the same folder as the script:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ fly -t k8s login -c http://localhost:8080 -u concourse -p concourse</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Next, run the following command to create the pipeline:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ ./set_pipeline.sh github-webhook k8s credentials-k8s.yml</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect3">
<h4 id="concourse-pipeline-run-k8s"><a class="link" href="#concourse-pipeline-run-k8s">Run the <code>github-webhook</code> Pipeline</a></h4>
<div class="paragraph">
<p>The following images show the various steps involved in runnig the <code>github-webhook</code> pipeline:</p>
</div>
<div class="paragraph">
<p>&#160;
&#160;</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/concourse/concourse_login.png" alt="concourse login">
</div>
<div class="title">Step 1: Click <code>Login</code></div>
</div>
<div class="paragraph">
<p>&#160;
&#160;</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/concourse/concourse_team_main.png" alt="concourse team main">
</div>
<div class="title">Step 2: Pick <code>main</code> team</div>
</div>
<div class="paragraph">
<p>&#160;
&#160;</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/concourse/concourse_user_pass.png" alt="concourse user pass">
</div>
<div class="title">Step 3: Log in with <code>concourse</code> user and <code>concourse</code> password</div>
</div>
<div class="paragraph">
<p>&#160;
&#160;</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/concourse/concourse_pipeline.png" alt="concourse pipeline">
</div>
<div class="title">Step 4: Your screen should look more or less like this</div>
</div>
<div class="paragraph">
<p>&#160;
&#160;</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/concourse/start_pipeline.png" alt="start pipeline">
</div>
<div class="title">Step 5: Unpause the pipeline by clicking in the top lefr corner and then clicking the <code>play</code> button</div>
</div>
<div class="paragraph">
<p>&#160;
&#160;</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/concourse/generate_version.png" alt="generate version">
</div>
<div class="title">Step 6: Click 'generate-version'</div>
</div>
<div class="paragraph">
<p>&#160;
&#160;</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/concourse/run_pipeline.png" alt="run pipeline">
</div>
<div class="title">Step 7: Click <code>+</code> sign to start a new build</div>
</div>
<div class="paragraph">
<p>&#160;
&#160;</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/concourse/concourse_pending.png" alt="concourse pending">
</div>
<div class="title">Step 8: The job is pending</div>
</div>
<div class="paragraph">
<p>&#160;
&#160;</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/concourse/job_running.png" alt="job running">
</div>
<div class="title">Step 9: Job is pending in the main screen</div>
</div>
<div class="paragraph">
<p>&#160;
&#160;</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/concourse/running_pipeline.png" alt="running pipeline">
</div>
<div class="title">Step 10: Job is running in the main screen</div>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="kubernetes-setup"><a class="link" href="#kubernetes-setup">Kubernetes Setup</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>This section describes how to set up Kubernetes.</p>
</div>
<div class="sect2">
<h3 id="kubernetes-cli-installation"><a class="link" href="#kubernetes-cli-installation">Kubernetes CLI Installation</a></h3>
<div class="paragraph">
<p>First, you need to install the <code>kubectl</code> command-line interface (CLI).</p>
</div>
<div class="sect3">
<h4 id="kubernetes-cli-script"><a class="link" href="#kubernetes-cli-script">Script Installation</a></h4>
<div class="paragraph">
<p>You can use the <code>tools/k8s-helper.sh</code> script to install <code>kubectl</code>. To do so, run the following script:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ ./tools/minikube-helper download-kubectl</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Then the <code>kubectl</code> gets downloaded.</p>
</div>
</div>
<div class="sect3">
<h4 id="kubernetes-cli-manual"><a class="link" href="#kubernetes-cli-manual">Manual Installation</a></h4>
<div class="paragraph">
<p>You can perform a manual installation for either OSX or Linux.</p>
</div>
<div class="sect4">
<h5 id="example-for-osx"><a class="link" href="#example-for-osx">Example for OSX</a></h5>
<div class="paragraph">
<p>The following listing shows how to manually install on OSX:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/darwin/amd64/kubectl
$ chmod +x ./kubectl
$ sudo mv ./kubectl /usr/local/bin/kubectl
----</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect4">
<h5 id="example-for-linux"><a class="link" href="#example-for-linux">Example for Linux</a></h5>
<div class="paragraph">
<p>The following listing shows how to manually install on Linux:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ curl -LO https://storage.googleapis.com/kubernetes-release/release/$(curl -s https://storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/linux/amd64/kubectl
$ chmod +x ./kubectl
$ sudo mv ./kubectl /usr/local/bin/kubectl</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>See <a href="https://kubernetes.io/docs/tasks/tools/install-kubectl/">this page</a> for more information.</p>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="start-minikube-k8s"><a class="link" href="#start-minikube-k8s">Kubernetes Cluster Setup</a></h3>
<div class="paragraph">
<p>We need a cluster of Kubernetes. The best choice is <a href="https://github.com/kubernetes/minikube">Minikube</a>.</p>
</div>
<div class="admonitionblock tip">
<table>
<tr>
<td class="icon">
<i class="fa icon-tip" title="Tip"></i>
</td>
<td class="content">
You can skip this step if you have a Kubernetes cluster installed and do not
want to use Minikube. In that case, the only thing you have to do is to set up spaces.
</td>
</tr>
</table>
</div>
<div class="admonitionblock warning">
<table>
<tr>
<td class="icon">
<i class="fa icon-warning" title="Warning"></i>
</td>
<td class="content">
Servers often run run out of resources at the stage step.
If that happens, <a href="#concourse-resources-k8s">clear some apps from PCF Dev and continue</a>.
</td>
</tr>
</table>
</div>
<div class="sect3">
<h4 id="kubernetes-minikube-script"><a class="link" href="#kubernetes-minikube-script">Script Installation</a></h4>
<div class="paragraph">
<p>You can use the <code>tools/k8s-helper.sh</code> script to install <code>Minikube</code>. To do so, run the following script:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ ./tools/minikube-helper download-minikube</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Then the <code>Minikube</code> cluster gets downloaded.</p>
</div>
</div>
<div class="sect3">
<h4 id="kubernetes-minikube-manual"><a class="link" href="#kubernetes-minikube-manual">Manual Installation</a></h4>
<div class="paragraph">
<p>You can perform a manual installation for either OSX or Linux.</p>
</div>
<div class="sect4">
<h5 id="example-for-osx-2"><a class="link" href="#example-for-osx-2">Example for OSX</a></h5>
<div class="paragraph">
<p>The following listing shows how to manually install on OSX:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.20.0/minikube-darwin-amd64 &amp;&amp; chmod +x minikube &amp;&amp; sudo mv minikube /usr/local/bin/</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Feel free to skip running <code>sudo mv minikube /usr/local/bin</code> if you want to add minikube to your path manually.</p>
</div>
</div>
</div>
<div class="sect3">
<h4 id="example-for-linux-2"><a class="link" href="#example-for-linux-2">Example for Linux</a></h4>
<div class="paragraph">
<p>The following listing shows how to manually install on Linux:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ curl -Lo minikube https://storage.googleapis.com/minikube/releases/v0.20.0/minikube-linux-amd64 &amp;&amp; chmod +x minikube &amp;&amp; sudo mv minikube /usr/local/bin/</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>You can skip running <code>sudo mv minikube /usr/local/bin</code> if you want to add minikube to your path manually.
See <a href="https://github.com/kubernetes/minikube/releases">this page</a> for more information on the installation.</p>
</div>
</div>
</div>
<div class="sect2">
<h3 id="run-minikube"><a class="link" href="#run-minikube">Run Minikube</a></h3>
<div class="paragraph">
<p>To start Kubernetes on your local box, run <code>minikube start</code>.</p>
</div>
<div class="paragraph">
<p>To add the dashboard, run <code>minikube dashboard</code>.</p>
</div>
</div>
<div class="sect2">
<h3 id="certificates-and-workers"><a class="link" href="#certificates-and-workers">Certificates and Workers</a></h3>
<div class="sect3">
<h4 id="minikube-certificates-and-workers"><a class="link" href="#minikube-certificates-and-workers">Minikube Certificates and Workers</a></h4>
<div class="paragraph">
<p>By default, if you install Minikube, all the certificates get installed in your
<code>~/.minikube</code> folder. Your <code>kubectl</code> configuration under <code>~/.kube/config</code> also
gets updated to use Minikube.</p>
</div>
</div>
<div class="sect3">
<h4 id="manual-certificates-and-workers-setup"><a class="link" href="#manual-certificates-and-workers-setup">Manual Certificates and Workers Setup</a></h4>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
If you want to run the default demo setup, you can skip this section.
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>To target a given Kubernetes instance, you need to pass around Certificate Authority
key and also user keys.</p>
</div>
<div class="paragraph">
<p>You can read more about the instructions on how to generate those keys <a href="https://coreos.com/kubernetes/docs/latest/openssl.html">here</a>.
Generally speaking, if you have a Kubernetes installation (such as <code>minikube</code>), this step
has already been done for you. Now you can reuse those keys on the workers.</p>
</div>
<div class="paragraph">
<p>The following inormation has been extracted from the <a href="https://coreos.com/kubernetes/docs/latest/configure-kubectl.html">Kubernetes official documentation</a>.</p>
</div>
<div class="paragraph">
<p>Configure <code>kubectl</code> to connect to the target cluster using the following commands, replacing the following values:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Replace <code>${MASTER_HOST}</code> with the master node address or name used in previous steps.</p>
</li>
<li>
<p>Replace <code>${CA_CERT}</code> with the absolute path to the <code>ca.pem</code> created in previous steps.</p>
</li>
<li>
<p>Replace <code>${ADMIN_KEY}</code> with the absolute path to the <code>admin-key.pem</code> created in previous steps.</p>
</li>
<li>
<p>Replace <code>${ADMIN_CERT}</code> with the absolute path to the <code>admin.pem</code> created in previous steps.</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>The following commands show how to perform these steps:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ kubectl config set-cluster default-cluster --server=https://${MASTER_HOST} --certificate-authority=${CA_CERT}
$ kubectl config set-credentials default-admin --certificate-authority=${CA_CERT} --client-key=${ADMIN_KEY} --client-certificate=${ADMIN_CERT}
$ kubectl config set-context default-system --cluster=default-cluster --user=default-admin
$ kubectl config use-context default-system</code></pre>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="generate-minikube-namespaces"><a class="link" href="#generate-minikube-namespaces">Generate Minikube Namespaces</a></h3>
<div class="paragraph">
<p>With the Minikube cluster running, we need to generate namespaces. To do so, run the
<code>./tools/k8s-helper.sh setup-namespaces</code>.</p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="the-demo-setup-cloud-foundry"><a class="link" href="#the-demo-setup-cloud-foundry">The demo setup (Cloud Foundry)</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>The demo uses two applications: <a href="https://github.com/spring-cloud-samples/github-webhook/">Github Webhook</a>
and <a href="https://github.com/spring-cloud-samples/github-analytics/">Github analytics code</a>. The following
image shows how these application communicate with each other:</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/demo/demo.png" alt="demo">
</div>
<div class="title">The overview of the demo: Github Webhook listens to HTTP calls and sends a message to Github Analytics</div>
</div>
<div class="paragraph">
<p>&#160;
&#160;</p>
</div>
<div class="paragraph">
<p>For the demo scenario we have two applications. <code>Github Analytics</code> and <code>Github Webhook</code>.
Let&#8217;s imagine a case where Github is emitting events via HTTP. <code>Github Webhook</code> has
an API that could register to such hooks and receive those messages. Once this happens
 <code>Github Webhook</code> sends a message by RabbitMQ to a channel. <code>Github Analytics</code> is
 listening to those messages and stores them in a MySQL database.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/demo/demo_metrics.png" alt="demo metrics">
</div>
<div class="title">Gathering metrics: Github Analytics exposes metrics that are polled by Prometheus</div>
</div>
<div class="paragraph">
<p>&#160;
&#160;</p>
</div>
<div class="paragraph">
<p><code>Github Analytics</code> has its KPIs (Key Performance Indicators) monitored. In the case
of that application the KPI is number of issues.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/demo/demo_alerting.png" alt="demo alerting">
</div>
<div class="title">Alerting over metrics: Grafana alerts Slack over Prometheus metrics</div>
</div>
<div class="paragraph">
<p>&#160;
&#160;</p>
</div>
<div class="paragraph">
<p>Let&#8217;s assume that if we go below the threshold of X issues then an alert should be
sent to Slack.</p>
</div>
<div class="sect2">
<h3 id="deploying-production-applications-to-pcf-dev"><a class="link" href="#deploying-production-applications-to-pcf-dev">Deploying Production Applications to PCF Dev</a></h3>
<div class="paragraph">
<p>In a real-world scenario, we would not want to automatically provision services such as
RabbitMQ, MySQL, or Eureka each time we deploy a new application to production. Typically,
production is provisioned manually (often by using automated solutions). In our case, before
you deploy to production, you can provision the <code>pcfdev-prod</code> space by using the
 <code>cf-helper.sh</code>. To do so, call the following script:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ ./cf-helper.sh setup-prod-infra</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>The CF CLI:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>Logs in to PCF Dev,</p>
</li>
<li>
<p>Targets the <code>pcfdev-prod</code> space</p>
</li>
<li>
<p>Sets up:</p>
<div class="ulist">
<ul>
<li>
<p>RabbitMQ (under the <code>rabbitmq-github</code> name)</p>
</li>
<li>
<p>MySQL (under <code>mysql-github-analytics</code> name)</p>
</li>
<li>
<p>Eureka (under <code>github-eureka</code> name)</p>
</li>
</ul>
</div>
</li>
</ul>
</div>
</div>
<div class="sect2">
<h3 id="running-prometheus-on-cf"><a class="link" href="#running-prometheus-on-cf">Running Prometheus on CF</a></h3>
<div class="paragraph">
<p>You can check out <a href="https://github.com/making/prometheus-on-PCF">Toshiaki Maki&#8217;s code</a> on how to automate Prometheus installation on CF.</p>
</div>
<div class="paragraph">
<p>Go to <a href="https://prometheus.io/download/" class="bare">https://prometheus.io/download/</a> and download the Linux binary. Then run the following command:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">cf push cloud-pipelines-prometheus -b binary_buildpack -c './prometheus -web.listen-address=:8080' -m 64m</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Also, <code>localhost:9090</code> in <code>prometheus.yml</code> should be <code>localhost:8080</code>.</p>
</div>
<div class="paragraph">
<p>The file should resemble the following listing to work with the demo setup (change <code>github-analytics-cloud-pipelines.cfapps.io</code>
to your <code>github-analytics</code> installation).</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-yml hljs" data-lang="yml"># my global config
global:
  scrape_interval:     15s # Set the scrape interval to every 15 seconds. Default is every 1 minute.
  evaluation_interval: 15s # Evaluate rules every 15 seconds. The default is every 1 minute.
  # scrape_timeout is set to the global default (10s).

  # Attach these labels to any time series or alerts when communicating with
  # external systems (federation, remote storage, Alertmanager).
  external_labels:
      monitor: 'codelab-monitor'

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
  # - "first.rules"
  # - "second.rules"

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:
  # The job name is added as a label `job=&lt;job_name&gt;` to any timeseries scraped from this config.
  - job_name: 'prometheus'

    # metrics_path defaults to '/metrics'
    # scheme defaults to 'http'.

    static_configs:
      - targets: ['localhost:8080']

  - job_name: 'demo-app'

    # Override the global default and scrape targets from this job every 5 seconds.
    scrape_interval: 5s

    metrics_path: '/prometheus'
    # scheme defaults to 'http'.

    static_configs:
      - targets: ['github-analytics-cloud-pipelines.cfapps.io']</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>A deployed version for the Cloud Pipelines demo is available <a href="https://cloud-pipelines-prometheus.cfapps.io/">here</a>.</p>
</div>
</div>
<div class="sect2">
<h3 id="running-grafana-on-cf"><a class="link" href="#running-grafana-on-cf">Running Grafana on CF</a></h3>
<div class="paragraph">
<p>You can check out <a href="https://github.com/making/cf-grafana">Toshiaki Maki&#8217;s code</a> to see how to automate Prometheus installation on CF.</p>
</div>
<div class="paragraph">
<p>Download the tarball from <a href="https://grafana.com/grafana/download?platform=linux" class="bare">https://grafana.com/grafana/download?platform=linux</a>
and set <code>http_port = 8080</code> in <code>conf/default.ini</code>. Then run the following the command:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">cf push cloud-pipelines-grafana -b binary_buildpack -c './bin/grafana-server web' -m 64m</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>The demo uses Grafana Dashboard with an ID of <code>2471</code>.</p>
</div>
<div class="paragraph">
<p>A deployed version for the Cloud Pipelines demo is available <a href="https://cloud-pipelines-grafana.cfapps.io/">here</a></p>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="the-demo-setup-kubernetes"><a class="link" href="#the-demo-setup-kubernetes">The demo setup (Kubernetes)</a></h2>
<div class="sectionbody">
<div class="paragraph">
<p>The demo uses two applications: <a href="https://github.com/spring-cloud-samples/github-webhook-kubernetes/">Github Webhook</a>
and <a href="https://github.com/spring-cloud-samples/github-analytics-kubernetes/">Github analytics code</a>. The following
image shows how these application communicate with each other:</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/demo/demo.png" alt="demo">
</div>
<div class="title">The overview of the demo: Github Webhook listens to HTTP calls and sends a message to Github Analytics</div>
</div>
<div class="paragraph">
<p>&#160;
&#160;</p>
</div>
<div class="paragraph">
<p>For the demo scenario we have two applications. <code>Github Analytics</code> and <code>Github Webhook</code>.
Let&#8217;s imagine a case where Github is emitting events via HTTP. <code>Github Webhook</code> has
an API that could register to such hooks and receive those messages. Once this happens
 <code>Github Webhook</code> sends a message by RabbitMQ to a channel. <code>Github Analytics</code> is
 listening to those messages and stores them in a MySQL database.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/demo/demo_metrics.png" alt="demo metrics">
</div>
<div class="title">Gathering metrics: Github Analytics exposes metrics that are polled by Prometheus</div>
</div>
<div class="paragraph">
<p>&#160;
&#160;</p>
</div>
<div class="paragraph">
<p><code>Github Analytics</code> has its KPIs (Key Performance Indicators) monitored. In the case
of that application the KPI is number of issues.</p>
</div>
<div class="imageblock">
<div class="content">
<img src="https://raw.githubusercontent.com/CloudPipelines/concourse/master/docs/images/demo/demo_alerting.png" alt="demo alerting">
</div>
<div class="title">Alerting over metrics: Grafana alerts Slack over Prometheus metrics</div>
</div>
<div class="paragraph">
<p>&#160;
&#160;</p>
</div>
<div class="paragraph">
<p>Let&#8217;s assume that if we go below the threshold of X issues then an alert should be
sent to Slack.</p>
</div>
<div class="sect2">
<h3 id="deploying-production-applications-to-minikube"><a class="link" href="#deploying-production-applications-to-minikube">Deploying Production Applications to Minikube</a></h3>
<div class="paragraph">
<p>In a real-world scenario, we would not want to automatically provision services such as
RabbitMQ, MySQL, or Eureka each time we deploy a new application to production. Typically,
production is provisioned manually (often by using automated solutions). In our case, before
you deploy to production, you can provision the <code>cloud-pipelines-prod</code> namespace by using the
 <code>k8s-helper.sh</code>. To do so, call the following script:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ ./k8s-helper.sh setup-prod-infra</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="running-prometheus-on-kubernetes"><a class="link" href="#running-prometheus-on-kubernetes">Running Prometheus on Kubernetes</a></h3>
<div class="paragraph">
<p>Use Helm to install Prometheus. Later in this demo, we point it to the services
deployed to our cluster.</p>
</div>
<div class="paragraph">
<p>Create a file called <code>values.yaml</code> with the following content:</p>
</div>
<div class="exampleblock">
<div class="title">Example 1. values.yaml</div>
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-yml hljs" data-lang="yml">rbac:
  create: false

alertmanager:
  ## If false, alertmanager will not be installed
  ##
  enabled: true

  # Defines the serviceAccountName to use when `rbac.create=false`
  serviceAccountName: default

  ## alertmanager container name
  ##
  name: alertmanager

  ## alertmanager container image
  ##
  image:
    repository: prom/alertmanager
    tag: v0.9.1
    pullPolicy: IfNotPresent

  ## Additional alertmanager container arguments
  ##
  extraArgs: {}

  ## The URL prefix at which the container can be accessed. Useful in the case the '-web.external-url' includes a slug
  ## so that the various internal URLs are still able to access as they are in the default case.
  ## (Optional)
  baseURL: ""

  ## Additional alertmanager container environment variable
  ## For instance to add a http_proxy
  ##
  extraEnv: {}

  ## ConfigMap override where fullname is {{.Release.Name}}-{{.Values.alertmanager.configMapOverrideName}}
  ## Defining configMapOverrideName will cause templates/alertmanager-configmap.yaml
  ## to NOT generate a ConfigMap resource
  ##
  configMapOverrideName: ""

  ingress:
    ## If true, alertmanager Ingress will be created
    ##
    enabled: false

    ## alertmanager Ingress annotations
    ##
    annotations: {}
    #   kubernetes.io/ingress.class: nginx
    #   kubernetes.io/tls-acme: 'true'

    ## alertmanager Ingress hostnames
    ## Must be provided if Ingress is enabled
    ##
    hosts: []
    #   - alertmanager.domain.com

    ## alertmanager Ingress TLS configuration
    ## Secrets must be manually created in the namespace
    ##
    tls: []
    #   - secretName: prometheus-alerts-tls
    #     hosts:
    #       - alertmanager.domain.com

  ## Alertmanager Deployment Strategy type
  # strategy:
  #   type: Recreate

  ## Node labels for alertmanager pod assignment
  ## Ref: https://kubernetes.io/docs/user-guide/node-selection/
  ##
  nodeSelector: {}

  persistentVolume:
    ## If true, alertmanager will create/use a Persistent Volume Claim
    ## If false, use emptyDir
    ##
    enabled: true

    ## alertmanager data Persistent Volume access modes
    ## Must match those of existing PV or dynamic provisioner
    ## Ref: https://kubernetes.io/docs/user-guide/persistent-volumes/
    ##
    accessModes:
      - ReadWriteOnce

    ## alertmanager data Persistent Volume Claim annotations
    ##
    annotations: {}

    ## alertmanager data Persistent Volume existing claim name
    ## Requires alertmanager.persistentVolume.enabled: true
    ## If defined, PVC must be created manually before volume will be bound
    existingClaim: ""

    ## alertmanager data Persistent Volume mount root path
    ##
    mountPath: /data

    ## alertmanager data Persistent Volume size
    ##
    size: 2Gi

    ## alertmanager data Persistent Volume Storage Class
    ## If defined, storageClassName: &lt;storageClass&gt;
    ## If set to "-", storageClassName: "", which disables dynamic provisioning
    ## If undefined (the default) or set to null, no storageClassName spec is
    ##   set, choosing the default provisioner.  (gp2 on AWS, standard on
    ##   GKE, AWS &amp; OpenStack)
    ##
    # storageClass: "-"

    ## Subdirectory of alertmanager data Persistent Volume to mount
    ## Useful if the volume's root directory is not empty
    ##
    subPath: ""

  ## Annotations to be added to alertmanager pods
  ##
  podAnnotations: {}

  replicaCount: 1

  ## alertmanager resource requests and limits
  ## Ref: https://kubernetes.io/docs/user-guide/compute-resources/
  ##
  resources: {}
    # limits:
    #   cpu: 10m
    #   memory: 32Mi
    # requests:
    #   cpu: 10m
    #   memory: 32Mi

  service:
    annotations: {}
    labels: {}
    clusterIP: ""

    ## List of IP addresses at which the alertmanager service is available
    ## Ref: https://kubernetes.io/docs/user-guide/services/#external-ips
    ##
    externalIPs: []

    loadBalancerIP: ""
    loadBalancerSourceRanges: []
    servicePort: 80
    # nodePort: 30000
    type: ClusterIP

## Monitors ConfigMap changes and POSTs to a URL
## Ref: https://github.com/jimmidyson/configmap-reload
##
configmapReload:
  ## configmap-reload container name
  ##
  name: configmap-reload

  ## configmap-reload container image
  ##
  image:
    repository: jimmidyson/configmap-reload
    tag: v0.1
    pullPolicy: IfNotPresent

  ## configmap-reload resource requests and limits
  ## Ref: https://kubernetes.io/docs/user-guide/compute-resources/
  ##
  resources: {}

kubeStateMetrics:
  ## If false, kube-state-metrics will not be installed
  ##
  enabled: true

  # Defines the serviceAccountName to use when `rbac.create=false`
  serviceAccountName: default

  ## kube-state-metrics container name
  ##
  name: kube-state-metrics

  ## kube-state-metrics container image
  ##
  image:
    repository: gcr.io/google_containers/kube-state-metrics
    tag: v1.1.0-rc.0
    pullPolicy: IfNotPresent

  ## Node labels for kube-state-metrics pod assignment
  ## Ref: https://kubernetes.io/docs/user-guide/node-selection/
  ##
  nodeSelector: {}

  ## Annotations to be added to kube-state-metrics pods
  ##
  podAnnotations: {}

  replicaCount: 1

  ## kube-state-metrics resource requests and limits
  ## Ref: https://kubernetes.io/docs/user-guide/compute-resources/
  ##
  resources: {}
    # limits:
    #   cpu: 10m
    #   memory: 16Mi
    # requests:
    #   cpu: 10m
    #   memory: 16Mi

  service:
    annotations:
      prometheus.io/scrape: "true"
    labels: {}

    clusterIP: None

    ## List of IP addresses at which the kube-state-metrics service is available
    ## Ref: https://kubernetes.io/docs/user-guide/services/#external-ips
    ##
    externalIPs: []

    loadBalancerIP: ""
    loadBalancerSourceRanges: []
    servicePort: 80
    type: ClusterIP

nodeExporter:
  ## If false, node-exporter will not be installed
  ##
  enabled: true

  # Defines the serviceAccountName to use when `rbac.create=false`
  serviceAccountName: default

  ## node-exporter container name
  ##
  name: node-exporter

  ## node-exporter container image
  ##
  image:
    repository: prom/node-exporter
    tag: v0.15.0
    pullPolicy: IfNotPresent

  ## Additional node-exporter container arguments
  ##
  extraArgs: {}

  ## Additional node-exporter hostPath mounts
  ##
  extraHostPathMounts: []
    # - name: textfile-dir
    #   mountPath: /srv/txt_collector
    #   hostPath: /var/lib/node-exporter
    #   readOnly: true

  ## Node tolerations for node-exporter scheduling to nodes with taints
  ## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
  ##
  tolerations: []
    # - key: "key"
    #   operator: "Equal|Exists"
    #   value: "value"
    #   effect: "NoSchedule|PreferNoSchedule|NoExecute(1.6 only)"

  ## Node labels for node-exporter pod assignment
  ## Ref: https://kubernetes.io/docs/user-guide/node-selection/
  ##
  nodeSelector: {}

  ## Annotations to be added to node-exporter pods
  ##
  podAnnotations: {}

  ## node-exporter resource limits &amp; requests
  ## Ref: https://kubernetes.io/docs/user-guide/compute-resources/
  ##
  resources: {}
    # limits:
    #   cpu: 200m
    #   memory: 50Mi
    # requests:
    #   cpu: 100m
    #   memory: 30Mi

  service:
    annotations:
      prometheus.io/scrape: "true"
    labels: {}

    clusterIP: None

    ## List of IP addresses at which the node-exporter service is available
    ## Ref: https://kubernetes.io/docs/user-guide/services/#external-ips
    ##
    externalIPs: []

    hostPort: 9100
    loadBalancerIP: ""
    loadBalancerSourceRanges: []
    servicePort: 9100
    type: ClusterIP

server:
  ## Prometheus server container name
  ##
  name: server

  # Defines the serviceAccountName to use when `rbac.create=false`
  serviceAccountName: default

  ## Prometheus server container image
  ##
  image:
    repository: prom/prometheus
    tag: v1.8.0
    pullPolicy: IfNotPresent

  ## (optional) alertmanager URL
  ## only used if alertmanager.enabled = false
  alertmanagerURL: ""

  ## The URL prefix at which the container can be accessed. Useful in the case the '-web.external-url' includes a slug
  ## so that the various internal URLs are still able to access as they are in the default case.
  ## (Optional)
  baseURL: ""

  ## Additional Prometheus server container arguments
  ##
  extraArgs: {}

  ## Additional Prometheus server hostPath mounts
  ##
  extraHostPathMounts: []
    # - name: certs-dir
    #   mountPath: /etc/kubernetes/certs
    #   hostPath: /etc/kubernetes/certs
    #   readOnly: true

  ## ConfigMap override where fullname is {{.Release.Name}}-{{.Values.server.configMapOverrideName}}
  ## Defining configMapOverrideName will cause templates/server-configmap.yaml
  ## to NOT generate a ConfigMap resource
  ##
  configMapOverrideName: ""

  ingress:
    ## If true, Prometheus server Ingress will be created
    ##
    enabled: false

    ## Prometheus server Ingress annotations
    ##
    annotations: {}
    #   kubernetes.io/ingress.class: nginx
    #   kubernetes.io/tls-acme: 'true'

    ## Prometheus server Ingress hostnames
    ## Must be provided if Ingress is enabled
    ##
    hosts: []
    #   - prometheus.domain.com

    ## Prometheus server Ingress TLS configuration
    ## Secrets must be manually created in the namespace
    ##
    tls: []
    #   - secretName: prometheus-server-tls
    #     hosts:
    #       - prometheus.domain.com

  ## Server Deployment Strategy type
  # strategy:
  #   type: Recreate

  ## Node tolerations for server scheduling to nodes with taints
  ## Ref: https://kubernetes.io/docs/concepts/configuration/assign-pod-node/
  ##
  tolerations: []
    # - key: "key"
    #   operator: "Equal|Exists"
    #   value: "value"
    #   effect: "NoSchedule|PreferNoSchedule|NoExecute(1.6 only)"

  ## Node labels for Prometheus server pod assignment
  ## Ref: https://kubernetes.io/docs/user-guide/node-selection/
  nodeSelector: {}

  persistentVolume:
    ## If true, Prometheus server will create/use a Persistent Volume Claim
    ## If false, use emptyDir
    ##
    enabled: true

    ## Prometheus server data Persistent Volume access modes
    ## Must match those of existing PV or dynamic provisioner
    ## Ref: https://kubernetes.io/docs/user-guide/persistent-volumes/
    ##
    accessModes:
      - ReadWriteOnce

    ## Prometheus server data Persistent Volume annotations
    ##
    annotations: {}

    ## Prometheus server data Persistent Volume existing claim name
    ## Requires server.persistentVolume.enabled: true
    ## If defined, PVC must be created manually before volume will be bound
    existingClaim: ""

    ## Prometheus server data Persistent Volume mount root path
    ##
    mountPath: /data

    ## Prometheus server data Persistent Volume size
    ##
    size: 8Gi

    ## Prometheus server data Persistent Volume Storage Class
    ## If defined, storageClassName: &lt;storageClass&gt;
    ## If set to "-", storageClassName: "", which disables dynamic provisioning
    ## If undefined (the default) or set to null, no storageClassName spec is
    ##   set, choosing the default provisioner.  (gp2 on AWS, standard on
    ##   GKE, AWS &amp; OpenStack)
    ##
    # storageClass: "-"

    ## Subdirectory of Prometheus server data Persistent Volume to mount
    ## Useful if the volume's root directory is not empty
    ##
    subPath: ""

  ## Annotations to be added to Prometheus server pods
  ##
  podAnnotations: {}
    # iam.amazonaws.com/role: prometheus

  replicaCount: 1

  ## Prometheus server resource requests and limits
  ## Ref: https://kubernetes.io/docs/user-guide/compute-resources/
  ##
  resources: {}
    # limits:
    #   cpu: 500m
    #   memory: 512Mi
    # requests:
    #   cpu: 500m
    #   memory: 512Mi

  service:
    annotations: {}
    labels: {}
    clusterIP: ""

    ## List of IP addresses at which the Prometheus server service is available
    ## Ref: https://kubernetes.io/docs/user-guide/services/#external-ips
    ##
    externalIPs: []

    loadBalancerIP: ""
    loadBalancerSourceRanges: []
    servicePort: 80
    type: ClusterIP

  ## Prometheus server pod termination grace period
  ##
  terminationGracePeriodSeconds: 300

  ## Prometheus data retention period (i.e 360h)
  ##
  retention: ""

pushgateway:
  ## If false, pushgateway will not be installed
  ##
  enabled: true

  ## pushgateway container name
  ##
  name: pushgateway

  ## pushgateway container image
  ##
  image:
    repository: prom/pushgateway
    tag: v0.4.0
    pullPolicy: IfNotPresent

  ## Additional pushgateway container arguments
  ##
  extraArgs: {}

  ingress:
    ## If true, pushgateway Ingress will be created
    ##
    enabled: false

    ## pushgateway Ingress annotations
    ##
    annotations:
    #   kubernetes.io/ingress.class: nginx
    #   kubernetes.io/tls-acme: 'true'

    ## pushgateway Ingress hostnames
    ## Must be provided if Ingress is enabled
    ##
    hosts: []
    #   - pushgateway.domain.com

    ## pushgateway Ingress TLS configuration
    ## Secrets must be manually created in the namespace
    ##
    tls: []
    #   - secretName: prometheus-alerts-tls
    #     hosts:
    #       - pushgateway.domain.com

  ## Node labels for pushgateway pod assignment
  ## Ref: https://kubernetes.io/docs/user-guide/node-selection/
  ##
  nodeSelector: {}

  ## Annotations to be added to pushgateway pods
  ##
  podAnnotations: {}

  replicaCount: 1

  ## pushgateway resource requests and limits
  ## Ref: https://kubernetes.io/docs/user-guide/compute-resources/
  ##
  resources: {}
    # limits:
    #   cpu: 10m
    #   memory: 32Mi
    # requests:
    #   cpu: 10m
    #   memory: 32Mi

  service:
    annotations:
      prometheus.io/probe: pushgateway
    labels: {}
    clusterIP: ""

    ## List of IP addresses at which the pushgateway service is available
    ## Ref: https://kubernetes.io/docs/user-guide/services/#external-ips
    ##
    externalIPs: []

    loadBalancerIP: ""
    loadBalancerSourceRanges: []
    servicePort: 9091
    type: ClusterIP

## alertmanager ConfigMap entries
##
alertmanagerFiles:
  alertmanager.yml: |-
    global:
      # slack_api_url: ''
    receivers:
      - name: default-receiver
        # slack_configs:
        #  - channel: '@you'
        #    send_resolved: true
    route:
      group_wait: 10s
      group_interval: 5m
      receiver: default-receiver
      repeat_interval: 3h
## Prometheus server ConfigMap entries
##
serverFiles:
  alerts: ""
  rules: ""

  prometheus.yml: |-
    rule_files:
      - /etc/config/rules
      - /etc/config/alerts
    scrape_configs:
      - job_name: 'demo-app'
        scrape_interval: 5s
        metrics_path: '/prometheus'
        static_configs:
          - targets:
            - github-analytics.cloud-pipelines-prod.svc.cluster.local:8080
      - job_name: prometheus
        static_configs:
          - targets:
            - localhost:9090
      # A scrape configuration for running Prometheus on a Kubernetes cluster.
      # This uses separate scrape configs for cluster components (i.e. API server, node)
      # and services to allow each to use different authentication configs.
      #
      # Kubernetes labels will be added as Prometheus labels on metrics via the
      # `labelmap` relabeling action.
      # Scrape config for API servers.
      #
      # Kubernetes exposes API servers as endpoints to the default/kubernetes
      # service so this uses `endpoints` role and uses relabelling to only keep
      # the endpoints associated with the default/kubernetes service using the
      # default named port `https`. This works for single API server deployments as
      # well as HA API server deployments.
      - job_name: 'kubernetes-apiservers'
        kubernetes_sd_configs:
          - role: endpoints
        # Default to scraping over https. If required, just disable this or change to
        # `http`.
        scheme: https
        # This TLS &amp; bearer token file config is used to connect to the actual scrape
        # endpoints for cluster components. This is separate to discovery auth
        # configuration because discovery &amp; scraping are two separate concerns in
        # Prometheus. The discovery auth config is automatic if Prometheus runs inside
        # the cluster. Otherwise, more config options have to be provided within the
        # &lt;kubernetes_sd_config&gt;.
        tls_config:
          ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
          # If your node certificates are self-signed or use a different CA to the
          # master CA, then disable certificate verification below. Note that
          # certificate verification is an integral part of a secure infrastructure
          # so this should only be disabled in a controlled environment. You can
          # disable certificate verification by uncommenting the line below.
          #
          insecure_skip_verify: true
        bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
        # Keep only the default/kubernetes service endpoints for the https port. This
        # will add targets for each API server which Kubernetes adds an endpoint to
        # the default/kubernetes service.
        relabel_configs:
          - source_labels: [__meta_kubernetes_namespace, __meta_kubernetes_service_name, __meta_kubernetes_endpoint_port_name]
            action: keep
            regex: default;kubernetes;https
      - job_name: 'kubernetes-nodes'
        # Default to scraping over https. If required, just disable this or change to
        # `http`.
        scheme: https
        # This TLS &amp; bearer token file config is used to connect to the actual scrape
        # endpoints for cluster components. This is separate to discovery auth
        # configuration because discovery &amp; scraping are two separate concerns in
        # Prometheus. The discovery auth config is automatic if Prometheus runs inside
        # the cluster. Otherwise, more config options have to be provided within the
        # &lt;kubernetes_sd_config&gt;.
        tls_config:
          ca_file: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
          # If your node certificates are self-signed or use a different CA to the
          # master CA, then disable certificate verification below. Note that
          # certificate verification is an integral part of a secure infrastructure
          # so this should only be disabled in a controlled environment. You can
          # disable certificate verification by uncommenting the line below.
          #
          insecure_skip_verify: true
        bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
        kubernetes_sd_configs:
          - role: node
        relabel_configs:
          - action: labelmap
            regex: __meta_kubernetes_node_label_(.+)
          - target_label: __address__
            replacement: kubernetes.default.svc:443
          - source_labels: [__meta_kubernetes_node_name]
            regex: (.+)
            target_label: __metrics_path__
            replacement: /api/v1/nodes/${1}/proxy/metrics
      # Scrape config for service endpoints.
      #
      # The relabeling allows the actual service scrape endpoint to be configured
      # via the following annotations:
      #
      # * `prometheus.io/scrape`: Only scrape services that have a value of `true`
      # * `prometheus.io/scheme`: If the metrics endpoint is secured then you will need
      # to set this to `https` &amp; most likely set the `tls_config` of the scrape config.
      # * `prometheus.io/path`: If the metrics path is not `/metrics` override this.
      # * `prometheus.io/port`: If the metrics are exposed on a different port to the
      # service then set this appropriately.
      - job_name: 'kubernetes-service-endpoints'
        kubernetes_sd_configs:
          - role: endpoints
        relabel_configs:
          - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scrape]
            action: keep
            regex: true
          - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_scheme]
            action: replace
            target_label: __scheme__
            regex: (https?)
          - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_path]
            action: replace
            target_label: __metrics_path__
            regex: (.+)
          - source_labels: [__address__, __meta_kubernetes_service_annotation_prometheus_io_port]
            action: replace
            target_label: __address__
            regex: (.+)(?::\d+);(\d+)
            replacement: $1:$2
          - action: labelmap
            regex: __meta_kubernetes_service_label_(.+)
          - source_labels: [__meta_kubernetes_namespace]
            action: replace
            target_label: kubernetes_namespace
          - source_labels: [__meta_kubernetes_service_name]
            action: replace
            target_label: kubernetes_name
      - job_name: 'prometheus-pushgateway'
        honor_labels: true
        kubernetes_sd_configs:
          - role: service
        relabel_configs:
          - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_probe]
            action: keep
            regex: pushgateway
      # Example scrape config for probing services via the Blackbox Exporter.
      #
      # The relabeling allows the actual service scrape endpoint to be configured
      # via the following annotations:
      #
      # * `prometheus.io/probe`: Only probe services that have a value of `true`
      - job_name: 'kubernetes-services'
        metrics_path: /probe
        params:
          module: [http_2xx]
        kubernetes_sd_configs:
          - role: service
        relabel_configs:
          - source_labels: [__meta_kubernetes_service_annotation_prometheus_io_probe]
            action: keep
            regex: true
          - source_labels: [__address__]
            target_label: __param_target
          - target_label: __address__
            replacement: blackbox
          - source_labels: [__param_target]
            target_label: instance
          - action: labelmap
            regex: __meta_kubernetes_service_label_(.+)
          - source_labels: [__meta_kubernetes_namespace]
            target_label: kubernetes_namespace
          - source_labels: [__meta_kubernetes_service_name]
            target_label: kubernetes_name
      # Example scrape config for pods
      #
      # The relabeling allows the actual pod scrape endpoint to be configured via the
      # following annotations:
      #
      # * `prometheus.io/scrape`: Only scrape pods that have a value of `true`
      # * `prometheus.io/path`: If the metrics path is not `/metrics` override this.
      # * `prometheus.io/port`: Scrape the pod on the indicated port instead of the default of `9102`.
      - job_name: 'kubernetes-pods'
        kubernetes_sd_configs:
          - role: pod
        relabel_configs:
          - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_scrape]
            action: keep
            regex: true
          - source_labels: [__meta_kubernetes_pod_annotation_prometheus_io_path]
            action: replace
            target_label: __metrics_path__
            regex: (.+)
          - source_labels: [__address__, __meta_kubernetes_pod_annotation_prometheus_io_port]
            action: replace
            regex: (.+):(?:\d+);(\d+)
            replacement: ${1}:${2}
            target_label: __address__
          - action: labelmap
            regex: __meta_kubernetes_pod_label_(.+)
          - source_labels: [__meta_kubernetes_namespace]
            action: replace
            target_label: kubernetes_namespace
          - source_labels: [__meta_kubernetes_pod_name]
            action: replace
            target_label: kubernetes_pod_name
networkPolicy:
  ## Enable creation of NetworkPolicy resources.
  ##
  enabled: false</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Next, create the prometheus installation with the predefined values. To do so, run the following command:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ helm install --name cloud-pipelines-prometheus stable/prometheus -f values.yaml</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Then you should see the following output:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">NOTES:
The Prometheus server can be accessed via port 80 on the following DNS name from within your cluster:
cloud-pipelines-prometheus-prometheus-server.default.svc.cluster.local


Get the Prometheus server URL by running these commands in the same shell:
  export POD_NAME=$(kubectl get pods --namespace default -l "app=prometheus,component=server" -o jsonpath="{.items[0].metadata.name}")
  kubectl --namespace default port-forward $POD_NAME 9090


The Prometheus alertmanager can be accessed via port 80 on the following DNS name from within your cluster:
cloud-pipelines-prometheus-prometheus-alertmanager.default.svc.cluster.local


Get the Alertmanager URL by running these commands in the same shell:
  export POD_NAME=$(kubectl get pods --namespace default -l "app=prometheus,component=alertmanager" -o jsonpath="{.items[0].metadata.name}")
  kubectl --namespace default port-forward $POD_NAME 9093


The Prometheus PushGateway can be accessed via port 9091 on the following DNS name from within your cluster:
cloud-pipelines-prometheus-prometheus-pushgateway.default.svc.cluster.local


Get the PushGateway URL by running these commands in the same shell:
  export POD_NAME=$(kubectl get pods --namespace default -l "app=prometheus,component=pushgateway" -o jsonpath="{.items[0].metadata.name}")
  kubectl --namespace default port-forward $POD_NAME 9093

For more information on running Prometheus, visit:
https://prometheus.io/</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect2">
<h3 id="running-grafana-on-kubernetes"><a class="link" href="#running-grafana-on-kubernetes">Running Grafana on Kubernetes</a></h3>
<div class="paragraph">
<p>Use Helm to install Grafana, by running the following command:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ helm install --name cloud-pipelines-grafana stable/grafana</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>You should see the following output:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">NOTES:
1. Get your 'admin' user password by running:

   kubectl get secret --namespace default cloud-pipelines-grafana-grafana -o jsonpath="{.data.grafana-admin-password}" | base64 --decode ; echo

2. The Grafana server can be accessed via port 80 on the following DNS name from within your cluster:

   cloud-pipelines-grafana-grafana.default.svc.cluster.local

   Get the Grafana URL to visit by running these commands in the same shell:

     export POD_NAME=$(kubectl get pods --namespace default -l "app=cloud-pipelines-grafana-grafana,component=grafana" -o jsonpath="{.items[0].metadata.name}")
     kubectl --namespace default port-forward $POD_NAME 3000

3. Login with the password from step 1 and the username: admin</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Perform the steps listed in the preceding output and add the Grafana&#8217;s datasource
as Prometheus with the following URL: <code><a href="https://cloud-pipelines-prometheus-prometheus-server.default.svc.cluster.local" class="bare">https://cloud-pipelines-prometheus-prometheus-server.default.svc.cluster.local</a></code></p>
</div>
<div class="paragraph">
<p>You can pick up the dashboard with the Grafana ID (2471). This is the
default dashboard for the Cloud Pipelines demo apps.</p>
</div>
<div class="paragraph">
<p>If you have both apps (<code>github-webhook</code> and <code>github-analytics</code>) running on production,
you can now trigger the messages. Download the JSON with a sample request
from <a href="https://github.com/marcingrzejszczak/github-webhook-kubernetes/blob/master/src/test/resources/github-webhook-input/hook-created.json">the github-webhook repository</a>.
Next, pick one of the <code>github-webhook</code> pods and forward its port
locally to a port <code>9876</code>, as follows:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ kubectl port-forward --namespace=cloud-pipelines-prod $( kubectl get pods --namespace=cloud-pipelines-prod | grep github-webhook | head -1 | awk '{print $1}' ) 9876:8080</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Next, send a couple of requests (more than four), by using cURL as follows:</p>
</div>
<div class="exampleblock">
<div class="content">
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-bash hljs" data-lang="bash">$ curl -X POST http://localhost:9876/ -d @path/to/issue-created.json \
--header "Content-Type: application/json"</code></pre>
</div>
</div>
</div>
</div>
<div class="paragraph">
<p>Then, if you use Grafana, you can see that you went above the threshold.</p>
</div>
</div>
</div>
</div>
</div>
<link rel="stylesheet" href="js/highlight/styles/atom-one-dark-reasonable.min.css">
<script src="js/highlight/highlight.min.js"></script>
<script>hljs.initHighlighting()</script>
</body>
</html>